#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2024/2/1 下午10:59
# @Author : Shi Lei
# @File : Main.py
import time
import os
import json
import re
import RWConfig as cfg  # 配置文件读写模块SHL
import PublicFunction as pf
from Log import logger  # 写日志模块SHL
from Subprocess import subprocess_Popen as POpen


class TurnToMp4:
    m4s_folder = ''  # 视频路径
    only_command_statement = '1' #只生成命令行语句，不调用ffmeg做转换，后期可以拷贝文件到其它地方再做转换

    def __init__(self):
        # 获取当前工作目录
        self.load_config()

    def clean_folder_name(self, folder_name):
        # 定义不允许的字符
        forbidden_chars = r'[\\/:"*?<>|]'  # Windows 不允许的字符
        # 可以根据需要添加更多字符，例如 macOS/Linux 的 /
        # forbidden_chars = r'[\\/:"*?<>|/]'

        # 使用正则表达式替换不允许的字符为空字符串
        cleaned_name = re.sub(forbidden_chars, '', folder_name)

        return cleaned_name

    def read_json_file(self,file_path):
        """
        讀取Json文件
        :param file_path:
        :return:
        """
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                data = json.load(file)
            # print(data)
        except:
            pass
        return data

    def get_file_name(self,data):
        """
        從json文件中讀取tabName的值作爲文件名
        :param data:
        :return:
        """
        try:
            title = data.get('title', '')
            filename = self.clean_folder_name(title)
        except:
            filename = ''
        # print(filename)
        return filename

    def get_source_file(self):
        logger.info("开始扫描M4S文件：{0}...".format(self.m4s_folder))
        rst = pf.find_files(self.m4s_folder, 'm4s') # 保存函数返回值
        lst_path = [] # 路径列表：用于判断文件夹里包含m4s文件的个数，如果不等于2则说明文件夹无效，不予做转换处理
        lst_file =[]
        if len(rst) > 0:
            for tup in rst:
                lst_path.append(tup[0])
                lst_file.append(tup[1])
                # print(tup[0], tup[1])
            lst_path = list(set(lst_path))  # 去重
        if len(lst_file)==0:
            logger.info("没有找到要处理的视频文件，查询的结果（列表）为空")
        return lst_path,lst_file

    def m4s_to_mp4(self):
        # 路径列表：用于判断文件夹里包含m4s文件的个数，如果不等于2则说明文件夹无效，不予做转换处理
        lst_path,lst_file = self.get_source_file()
        if len(lst_file)==0:
            return

        i =1 # 计数器，从1开始
        for path in lst_path:
            # 分割文件路径为目录列表
            dirs = path.split("/")
            # 获取最后一级文件夹名
            dir = dirs[-1] if len(dirs) > 1 else path  # 如果是在当前程序所在的文件夹下且只有一级目录，则len(dirs)=0,如:[当前文件夹下/]1384707303/1384707303-1-30080.m4s
            # print(path,dir)
            # 从文件列表中取出path下的每个文件名，如果数量等于2，则调用ffmpeg进行转换，否则提示错误返回，
            source = []
            for file in lst_file:
                if path in file:
                    source.append(file)
            if len(source) !=2:
                logger.error("{0}下包含的m4s文件数不是2(个)不予处理".format(path))
                continue
            # 开始转换 ffmpeg -i a.m4s -i b.m4s -c copy out.mp4
            total = len(lst_path)
            logger.info("开始处理({0}/{1})：{2}".format(i, total, path))
            info = self.read_json_file(path+'/videoInfo.json')
            # 獲取文件名
            filename = self.get_file_name(info)
            if len(filename) ==0:
                dest_file = "{0}.mp4".format(path+'/'+dir)   # 用最后一级文件夹名作为文件名
            else:
                dest_file = "{0}.mp4".format(path + '/' + filename)  # 從videoInfo文件中讀取到的tabName作爲文件名
            # 如果過去已經轉換過了，則跳過
            if os.path.exists(dest_file):
                logger.error("{0}已轉換過了,跳過".format(dest_file))
                continue
            # 開始轉換
            cmd = u'ffmpeg -i {0} -i {1} -c copy {2}'.format(source[0]+'new', source[1]+'new',dest_file)
            try:
                if self.only_command_statement == '0': # =0:做 m4s 转换 mp4  =1:仅生成命令行语句
                    POpen(source[0]+'new', source[1]+'new', dest_file)
                else:
                    logger.debug("{0}".format(cmd))
                i += 1
            except Exception as e:
                logger.error(e)
                continue


    def load_config(self):
        '''
        从配置文件中读取参数,若配置文件不存在，则搜索目录设为当前文件夹下，参数取默认值
        :return:
        '''
        """"""
        self.m4s_folder, self.only_command_statement = cfg.ReadToolConf()
        cFile_path = os.path.join(pf.get_basic_path()+'/'+pf.get_config_dir(), cfg.cFile)
        if os.path.exists(cFile_path):  # 容器部署运行环境
            self.m4s_folder = os.path.join(pf.get_basic_path(), self.m4s_folder)
        else:
            cFile_path = os.path.join(pf.get_config_dir(),cfg.cFile)  # 非容器环境打开程序，调试环境

        if (len(self.m4s_folder)==0 ) or (not os.path.exists(cFile_path)):
            self.m4s_folder=pf.get_current_directory()
            self.only_command_statement ='1'

    def truncate(self):
        '''
        批量对m4s视频文件做头部处理
        :return: 不返回值
        '''
        lst_path,lst_file = self.get_source_file()
        if len(lst_file)==0:
            return
        i = 0  # 计数器，从1开始
        for file in lst_file:
            if self.truncate_file(file):
                logger.debug("已处理:{0}".format(file))
            else:
                logger.debug("未处理:{0}".format(file))
            i = i+1
        logger.info("共处理:{0}个mt4文件".format(i))

    def truncate_file(self, filename):
        # 对单个文件进行处理，打开二进制文件,去掉头部为0的字节后重新保存为新文件
        try:
            with open(filename, 'rb+') as file:
                rd8 = file.read(8)
                if rd8 == b'00000000':
                    # 移动文件指针到目标位置
                    file.seek(9)
                    # 获取当前位置之后的所有字节
                    remaining_bytes = file.read()
                    '''
                    # 计算要保留的字节长度
                    new_length = len(remaining_bytes)
                    # 重新设置文件大小为新的长度
                    file.truncate(new_length)
                    # 将剩余的字节写回文件
                    file.write(remaining_bytes)
                    '''
                    with open(filename+'new', 'wb') as file2:
                        # 将内容写入文件
                        file2.write(remaining_bytes)
                    return True
                else: return False
        except Exception as e:
            logger.error(e)
            return False

    def convert(self):
        source, dest = self.get_files()
        # print(source)
        # print(dest)
        i = 0
        total = len(source)
        print('{0} 总 {1} 个'.format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), total))
        while i < total:
            cmd = u'{0} -i "{1}" -c:v libx264 -c:a copy -threads 5 -preset veryfast "{2}"'.format(self.ffmpeg,
                                                                                                  source[i], dest[i])
            print('{0} 当前第 {1}/{2} 个:{3}'.format(time.strftime("%Y-%m-%d %H:%M:%S",
                                                               time.localtime()), i+1, total, source[i]))
            logger.info(cmd)
            POpen(cmd)
            i += 1

    def openfile(filename):
        f = open(filename, mode='rb')
        try:
            data = f.read()
            print(data)
        finally:
            f.close()


